/***************************************************************************
 创建者: 华磊
 开始时间: 2020.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2020.5.8 类的具体实现代码编写

 ***************************************************************************
 *  @file x.h
 *  功能:
 *
 *                                                                         *
 ***************************************************************************/
#ifndef ECATIO_H
#define ECATIO_H

#include "ecattype.h"
#include "domparser.h"

#include <QVector>



#define D_MAX_IO_INDEX 10000

//写io不是线程安全
#define EC_READ_BIT(DATA, POS) ((*((uint8_t *) (DATA)) >> (POS)) & 0x01)
#define EC_WRITE_BIT(DATA, POS, VAL) \
    do { \
        if (VAL) *((uint8_t *) (DATA)) |=  (1 << (POS)); \
        else     *((uint8_t *) (DATA)) &= ~(1 << (POS)); \
    } while (0)



/// io模块对象字典数据偏移（内部使用）
struct EcatIoDeviceDataOffset{
    unsigned int  byte_offset;
    unsigned int  bit_offset;
    unsigned int  all_bit_offset;
    unsigned int  byte_offset_others[50];
    unsigned int  bit_offset_others[50];
};

/// io数据结构（内部使用）
struct EcatIoDeviceDataOffsetList{
    QVector<EcatIoDeviceDataOffset> ioDi;
    QVector<EcatIoDeviceDataOffset> ioDo;
    QVector<EcatIoDeviceDataOffset> ioAi;
    QVector<EcatIoDeviceDataOffset> ioAo;
    QVector<EcatIoDeviceDataOffset> ioEncoder;
    QVector<EcatIoDeviceDataOffset> ioControlWorld;//控制字，设置模式
    QVector<EcatIoDeviceDataOffset> ioStatus;//状态字
};


/**
 * @brief The EcatIo class io抽象类
 */
class EcatIo : public DomParser
{
public:
    EcatIo(E_DEVICE_PROTOCOL protocolIn, int aliasIn,int busIdIn);

public:
    int initialProperty(unsigned int vendorIdIn, unsigned int productCodeIn, int diCountIn,
                        int doCountIn, int aiCountIn, int aoCountIn, int encoderCountIn,
                        int controlCounterIn, int statusCounterIn);
    int setCount(int diCounter, int doCounter, int aiCounter, int aoCounter);
    int getAlias();
    bool  getDi(int index);//ethercat 专用
    float getAi(int index);//ethercat 专用
    void  setDo(int index, bool val);//ethercat 专用
    void  setAo(int index, float val);//ethercat 专用
    bool  getDo(int index);//ethercat 专用
    float getAo(int index);//ethercat 专用
    int getEncoderValue(int index);//ethercat 专用
    int getEncoderValue(std::vector<int> &encoderValueOut);//ethercat 专用



    /**
     * @brief updateDo: 放ethercat线程周期执行
     */
    void updateEthercatDo();

    int setSdoList(QVector<SdoConfig> &sdoConfigListIn);
    int getSdoList(QVector<SdoConfig> &sdoConfigListOut);

private:
    void setBitForCharArry(unsigned char* ptr, char bit, bool val);
    bool getBitForCharArry(unsigned char* ptr, char bit);
    void setBitForShortArry(unsigned short* ptr, char bit, bool val);
    bool getBitForShortArry(unsigned short *ptr, char bit);

public:
        int diCount;//物理
        int doCount;//物理
        int aiCount;//物理
        int aoCount;//物理
        int encoderCount;//编码器个数
        int controlCount;//控制字个数
        int statusCount;
        int nodeId;//ETHERCAT用

        //modbus设备内存数据
        bool modbus_diMemory[D_MAX_IO_INDEX];
        bool modbus_doMemory[D_MAX_IO_INDEX];

        //can设备内存数据
        bool can_diMemory[D_MAX_IO_INDEX];
        bool can_doMemory[D_MAX_IO_INDEX];
        double can_aiMemory[D_MAX_IO_INDEX];
        double can_aoMemory[D_MAX_IO_INDEX];

        //ethercat 内存数据缓存
        unsigned char p_ioDi[D_MAX_IO_INDEX/8];
        unsigned char p_ioDo[D_MAX_IO_INDEX/8];
        unsigned short p_ioDi_short[D_MAX_IO_INDEX/16];
        unsigned short p_ioDo_short[D_MAX_IO_INDEX/16];
        double p_ioAi[D_MAX_IO_INDEX];
        double p_ioAo[D_MAX_IO_INDEX];
        int p_ioEncoder[D_MAX_IO_INDEX];//编码器
        int p_ioControlWorld[D_MAX_IO_INDEX];//aiao控制字
        int p_ioStatus[D_MAX_IO_INDEX];//status状态字

        EcatIoDeviceDataOffsetList ethercatPdoDataOffsetInfo;//pdo对象在过程域数据区的偏移地址。

        QVector<SdoConfig> sdoConfigList;//ethercat使用

public:
    unsigned char ioDo_one_output[D_MAX_IO_INDEX];//ethercat 专用
    E_DEVICE_PROTOCOL protocol;
    int alias;//can , modbus用
    int busId;//预留，如果需要同时支持多条modbus－rtu
    unsigned int vendorId;
    unsigned int productCode;//产品码


};


#endif // ECATIO_H
